//
//  LFLiveKit+Rx.swift
//  live
//
//  Created by melvyn on 2018/8/16.
//  Copyright © 2018 NEET. All rights reserved.
//

import Foundation
import RxSwift
import RxCocoa
import LFLiveKit
import Link

typealias LiveSession = LFLiveSession
extension LiveSession {
    static var `default`: LiveSession = {
        let audioConfiguration = LFLiveAudioConfiguration.default()
        let videoConfiguration = LFLiveVideoConfiguration.defaultConfiguration(for: .medium3)
    
        let session = LiveSession(audioConfiguration: audioConfiguration, videoConfiguration: videoConfiguration)!
        session.captureDevicePosition = .back
        session.showDebugInfo = true
        session.beautyLevel = 0.2
  
        return session
    }()
    
    func setGLView(_ view: UIView) {
        preView = view
    }
}

extension Reactive where Base: LFLiveSession {
    
    var delegate: DelegateProxy<LFLiveSession, LFLiveSessionDelegate> {
        return RxLiveSessionDelegateProxy.proxy(for: base)
    }
    
    var captureDevicePosition: Binder<AVCaptureDevice.Position> {
        return Binder(self.base) { session, pos in
            session.captureDevicePosition = pos
        }
    }
    
    var isRunning: Binder<Bool> {
        return Binder(self.base) { session, isRunning in
            session.running = isRunning
        }
    }
    
    var open: Binder<LiveStream> {
        return Binder(self.base) { session, stream in
            session.stopLive()
            
            guard let streamID = stream.key else { return }
            
            let streamInfo = LFLiveStreamInfo.init()
            streamInfo.url =
                APIClient.Route.RTMP.description + streamID
            streamInfo.streamId = streamID

//            let desktopURL = "/Users/melvyn/Desktop/" + streamID
//            session.saveLocalVideoPath = URL.init(fileURLWithPath: desktopURL)
//            session.saveLocalVideo = true

            #if DEBUG
            if session.showDebugInfo {
                print(streamInfo.url)
            }
            #endif
            session.startLive(streamInfo)
        }
    }
    
    var shutdown: Binder<Bool> {
        return Binder(self.base) { session, shutdown  in
            #if DEBUG
            print("Live session shutdown: \(shutdown)")
            #endif
            guard shutdown else {
                return
            }
            session.stopLive()
        }
    }
    
    var outputDEBUG: ControlEvent<(session: LFLiveSession?, output: LFLiveDebug?)> {
        let source = delegate.methodInvoked(#selector(LFLiveSessionDelegate.liveSession(_:debugInfo:)))
            .map({ a -> (session: LFLiveSession?, output: LFLiveDebug?) in
                return (
                    a[0] as? LFLiveSession,
                    a[1] as? LFLiveDebug
                )
            })
        
        return ControlEvent(events: source)
    }
    
    var outputError: ControlEvent<(session: LFLiveSession?, output: LFLiveSocketErrorCode)> {
        let source = delegate.methodInvoked(#selector(LFLiveSessionDelegate.liveSession(_:errorCode:)))
            .map({ a -> (session: LFLiveSession?, output: LFLiveSocketErrorCode) in
                return (
                    a[0] as? LFLiveSession,
                    LFLiveSocketErrorCode.init(rawValue: try transfer(a[1], to: UInt.self))!
                )
            })
        return ControlEvent(events: source)
    }
    
    var state: ControlEvent<(session: LFLiveSession?, output: LFLiveState)> {
        let source = delegate.methodInvoked(#selector(LFLiveSessionDelegate.liveSession(_:liveStateDidChange:)))
            .map({ a -> (session: LFLiveSession?, output: LFLiveState) in
                return (
                    a[0] as? LFLiveSession,
                    LFLiveState.init(rawValue: try transfer(a[1], to: UInt.self))!
                )
            })
        return ControlEvent(events: source)
    }
}

func transfer<T>(_ obj: Any, to: T.Type) throws -> T {
    guard let result = obj as? T else {
        throw RxCocoaError.castingError(object: obj, targetType: to)
    }
    return result
}


extension LFLiveSession: HasDelegate {
    public typealias Delegate = LFLiveSessionDelegate
}

open class RxLiveSessionDelegateProxy
    : DelegateProxy<LFLiveSession, LFLiveSessionDelegate>
    , DelegateProxyType
    , LFLiveSessionDelegate {
    
    public init(session: LFLiveSession) {
        super.init(parentObject: session, delegateProxy: RxLiveSessionDelegateProxy.self)
    }
    
    public static func registerKnownImplementations() {
        self.register { RxLiveSessionDelegateProxy(session: $0) }
    }
}


extension LFLiveState: CustomStringConvertible {
    public var description: String {
        switch self {
        case .error:
            return "连接出错"
        case .pending:
            return "连接中"
        case .ready:
            return "准备"
        case .refresh:
            return "正在刷新"
        case .start:
            return "已连接"
        case .stop:
            return "已断开"
        }
    }
}

extension LFLiveSocketErrorCode: CustomStringConvertible {
    public var description: String {
        switch self {
        case .connectSocket:
            return "连接socket失败"
        case .getStreamInfo:
            return "获取流媒体信息失败"
        case .preView:
            return "预览失败"
        case .reConnectTimeOut:
            return "重连服务器超时"
        case .verification:
            return "验证服务器失败"
        }
    }
}
